///////////////////////////////////////////////////////////////////////////////
////  (c) Chaichuk AU (chaichuk@mail.ru), 								   ////
////  2005, Chelyabinsk, NTC Privodnaya Tehnika (momentum@chel.surnet.ru)  ////
///////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

#include "../dcmd/dcmd_driver_api.h"
#include "iofuncs.h"
#include "anybus_pci.h"

#define DRIVER_VER 0x0100

/****************************************************************************
 * FUNCTION NAME: io_devctl
 *
 * DESCRIPTION  : 
 *
 * RETURN VALUE : 
 ***************************************************************************/
int io_devctl (resmgr_context_t *ctp, io_devctl_t *msg, RESMGR_OCB_T *ocb)
{
	int							sts;
	void						*data;
	int							nbytes;
	int							dcmd;
	int							len;
	int							*ptr;
	int							n;
	int							ch;
	int							i;
	
	abs_pci_board_t				*board;
	abs_module_t				*abs;
	
	dcmd_config_t				*config;
	dcmd_ch_data_t				*aio_ch_data;
	dcmd_reg_4_intr_pulse_t		*reg_4_intr;
	


	board = & ((abs_dpm_attr_t *)(ocb->attr))->board;
	abs = & board->abs_module;

	
/*
 *	WARNING:  check in main.c to see if you need to adjust the "nparts_max" and "msg_max_size"
*/


	// see if it's a standard POSIX-supported devctl()
	if ((sts = iofunc_devctl_default (ctp, msg, ocb)) != _RESMGR_DEFAULT) {
		return (sts);
	}

	// assign a pointer to the data area of the message
	data = _DEVCTL_DATA (*msg);

	// get other data that can't be wiped out before we wipe the data structure
	dcmd = msg -> i.dcmd;
	len = msg -> i.nbytes;
	memset (&msg -> o, 0, sizeof (msg -> o));

	// preset the number of bytes that we'll return to zero
	nbytes = 0;

	// check for all commands
	switch (dcmd) {

		case DCMD_GET_CONFIG:
			config = (dcmd_config_t*) data;
			config->n_di = abs->init_input_len * 8;
			config->n_do = abs->init_output_len * 8;
			config->n_ai = abs->init_input_len;
			config->n_ao = abs->init_output_len;
			config->version = DRIVER_VER;
			nbytes = sizeof (dcmd_config_t);
		break;
		
		case DCMD_GET_CH_DATA:
			aio_ch_data = (dcmd_ch_data_t*) data;
			if ((aio_ch_data->ch < 0) || (aio_ch_data->ch >= abs->init_input_len))
				return ECHRNG;
	
			aio_ch_data->value = abs->input_buf [aio_ch_data->ch];
			
			nbytes = sizeof (dcmd_ch_data_t);
		break;
		
		case DCMD_GET_N_CH_DATA:
			
			ptr = (int*) (data + offsetof (dcmd_n_ch_data_t, n));
			n = *ptr++;

			for (i = 0; i < n; i++) {
				ch = ptr [i];
				if ((ch < 0) || (ch >= abs->init_input_len)) {

				}
				else ptr [i] = abs->input_buf [ch];
					
			}
			
			nbytes = sizeof (msg_hdr_t) + (1 + n) * sizeof (int);
		break;
		
		case DCMD_GET_ALL_CH_DATA:
						
		break;		
		
		case DCMD_GET_BUFFERED_DATA:

		break;
		
		case DCMD_SET_CH_DATA:
			aio_ch_data = (dcmd_ch_data_t*) data;
			if ((aio_ch_data->ch < 0) || (aio_ch_data->ch >= abs->init_output_len))
				return ECHRNG;
	
			abs->output_buf [aio_ch_data->ch] = aio_ch_data->value;
			
		break;
		
		case DCMD_SET_N_CH_DATA:
			ptr = (int*) (data + offsetof (dcmd_n_ch_data_t, n));
			n = *ptr++;

			for (i = 0; i < (n << 1); i += 2) {
				ch = ptr [i];
				if ((ptr [i] < 0) || (ch >= abs->init_output_len)) {;

				}
				else abs->output_buf [ch] = ptr [i + 1];
			}						
			
		break;
		
		case DCMD_REG_4_INTR_PULSE:
			reg_4_intr = (dcmd_reg_4_intr_pulse_t*) data;			

		break;
	
		default:
			return (ENOSYS);
	}

	// return data (if any) to the client
	msg -> o.nbytes = nbytes;
	SETIOV (ctp -> iov, &msg -> o, sizeof (msg -> o) + nbytes);
	return (_RESMGR_NPARTS (1));
}